package com.monna.view;

import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.RelativeLayout;

import com.monna.listener.IGamesListener;
import com.monna.util.ACTION;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 数字方块父容器
 *
 * @author 廖梦青
 */
public class GamesLayout extends RelativeLayout {

    /**
     * 4行4列
     */
    public int column = 4;
    private GamesItem[] gamesItemViews = null;
    private int padding = 4;
    private boolean once = true;

    private GestureDetector gestureDetector;
    private IGamesListener gameListener;
    /**
     * isMergrHappen isMoveHappen用于判断是否要再生成一个随机数字
     */
    private boolean isMergrHappen = true;
    private boolean isMoveHappen = true;
    /**
     * 获得的分数
     */
    private int score = 0;

    final int FLING_MIN_DISTANCE = 50;

    public GamesLayout(Context context) {
        this(context, null, 0);
    }

    public GamesLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public GamesLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //padding = Math.min(getPaddingBottom(), getPaddingLeft());
        gestureDetector = new GestureDetector(context, new MyGestureDetector());
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        gestureDetector.onTouchEvent(event);
        return true;
    }

    /**
     * 构建初始布局，计算布局的宽度和高度
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //GamesLayoutView 的宽高，取宽高间的最小值，保证布局为正方形
        int length = Math.min(getMeasuredHeight(), getMeasuredWidth());
        //Item 宽高
        int childWidth = (length- padding*(column + 1)) / column;
        if (once) {
            if (gamesItemViews == null) {
                gamesItemViews = new GamesItem[column * column];
            }
            for (int i = 0; i < column * column; i++) {
                GamesItem item = new GamesItem(getContext());
                gamesItemViews[i] = item;
                item.setId(i + 1);
                //存储宽高信息到LayoutParams中
                RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(childWidth, childWidth);
                //所有列，设置左边距
                lp.leftMargin = padding;
                //最后列，设置右边距
                if ((i + 1) % column == 0) {
                    lp.rightMargin = padding;
                }
                //不是第一列。出现前一个Item的右边
                if (i % column != 0) {
                    lp.addRule(RelativeLayout.RIGHT_OF, gamesItemViews[i - 1].getId());
                }
                //不是第一行，且出现在上一个Item的下面
                if ((i + 1) > column) {
                    lp.topMargin = padding;
                    lp.addRule(RelativeLayout.BELOW, gamesItemViews[i - column].getId());
                }
                //动态添加View
                addView(item, lp);
            }
            //随机出现一个数字
            generateNum();
        }
        once = false;
        //修改布局空间,指定自己的宽高
        setMeasuredDimension(length, length);
    }

    /**
     * 生成新数字
     */
    private void generateNum() {
        //判断游戏是否结束
        if(checkOver(gamesItemViews, column)) {
            if (gameListener != null)
                gameListener.onGameOver();
        }
        if(isMergrHappen||isMoveHappen){
            Random random = new Random();
            int next = random.nextInt(column * column);
            GamesItem item = gamesItemViews[next];
            while (item.getNumber()!=0){
                next = random.nextInt(column * column);
                item = gamesItemViews[next];
            }
            item.setNumber(Math.random() > 0.5 ? 4 : 2 );
            isMoveHappen = isMergrHappen = false;
        }
    }

    /**
     * 判断游戏是否结束
     * @param gamesItemViews
     * @param column
     * @return
     */
    private boolean checkOver(GamesItem[] gamesItemViews, int column){
        if (!isFull(gamesItemViews)){
            return false;
        }
        for (int i = 0; i < column; i++){
            for (int j = 0; j < column; j++){
                int index = i * column +j;
                GamesItem item = gamesItemViews[index];
                //不是最后一列，则判断和它右边相邻一个数字是否相同
                if ((index + 1) % column != 0){
                    GamesItem itemright = gamesItemViews[index + 1];
                    if (item.getNumber() == itemright.getNumber()){
                        return false;
                    }
                }
                //不是第一列，则判断和他左边相邻一个数字是否相同
                if(index % column!=0){
                    GamesItem itemleft = gamesItemViews[index-1];
                    if(item.getNumber()==itemleft.getNumber())
                        return false;
                }
                //不是最后一行，则判断和他下边相邻一个数字是否相同
                if(index < column * (column - 1)){
                    GamesItem itembottom = gamesItemViews[index + column];
                    if(item.getNumber() == itembottom.getNumber())
                        return false;
                }
                //不是第一行，则判断和他上边相邻一个数字是否相同
                if(index + 1 > column){
                    GamesItem itemtop = gamesItemViews[index - column];
                    if(item.getNumber() == itemtop.getNumber())
                        return false;
                }
            }
        }
        return true;
    }

    /**
     * 判断方块容器是否已满
     * @param gamesItemViews
     * @return
     */
    private boolean isFull(GamesItem[] gamesItemViews){
        //检测所有位置是否都有除0以外的数字
        for (int i = 0; i < gamesItemViews.length; i++){
            if (gamesItemViews[i].getNumber() == 0){
                return false;
            }
        }
        return true;
    }

    public void setOnGameListener(IGamesListener gameListener){
        this.gameListener = gameListener;
    }

    /**
     * 处理手势操作
     * @author 廖梦青
     */
    public class MyGestureDetector implements GestureDetector.OnGestureListener {

        final int FLING_MIN_DISTANCE = 50;

        @Override
        public boolean onDown(MotionEvent e) {
            return false;
        }

        @Override
        public void onShowPress(MotionEvent e) {

        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return false;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {

        }

        /**
         * 确定手势方向
         * @param e1
         * @param e2
         * @param velocityX
         * @param velocityY
         * @return
         */
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            //x轴方向上用户手势移动距离
            float x = e2.getX() - e1.getX();
            //y轴方向上用户手势移动距离
            float y = e2.getY() - e1.getY();
            //判断用户手势移动方向，上下左右，并“移动”数字
            if (x > FLING_MIN_DISTANCE && Math.abs(velocityX) > Math.abs(velocityY)){
                action(ACTION.RIGHT);
            }
            if (x <- FLING_MIN_DISTANCE && Math.abs(velocityX) > Math.abs(velocityY)){
                action(ACTION.LEFT);
            }
            if (y > FLING_MIN_DISTANCE && Math.abs(velocityX) < Math.abs(velocityY)){
                action(ACTION.DOWN);
            }
            if (y <- FLING_MIN_DISTANCE && Math.abs(velocityX) < Math.abs(velocityY)){
                action(ACTION.UP);
            }
            return true;
        }

        /**
         * 根据手势处理方位
         * @param action
         */
        private void action(ACTION action){
            for (int i = 0; i < column; i++){
                List<GamesItem> row = new ArrayList<>();
                for (int j = 0; j < column; j++){
                    int index = getIndexByAction(action, i, j);
                    GamesItem item = gamesItemViews[index];
                    if (item.getNumber() != 0){
                        row.add(item);
                    }
                }
                for (int j = 0; j < column; j++){
                    int index = getIndexByAction(action, i, j);
                    GamesItem item = gamesItemViews[index];
                    if (row.size() > j){
                        if (item.getNumber() != row.get(j).getNumber()){
                            isMoveHappen = true;
                            break;
                        }
                    }
                }
                //合并相同的
                mergeItem(row);

                //设置合并后的值
                for (int j = 0; j < column; j++){
                    int index = getIndexByAction(action, i, j);
                    if (row.size() > j){
                        gamesItemViews[index].setNumber(row.get(j).getNumber());
                    }else {
                        gamesItemViews[index].setNumber(0);
                    }
                }
            }
            generateNum();
        }

        /**
         * 移动数字方块并积分
         * @param row
         */
        private void mergeItem(List<GamesItem> row){
            if (row.size() < 2){
                return;
            }
            for (int j = 0; j < row.size() - 1; j++){
                GamesItem item1 = row.get(j);
                GamesItem item2 = row.get(j + 1);
                if (item1.getNumber() == item2.getNumber()){
                    isMergrHappen = true;
                    int val = item1.getNumber() * 2;
                    item1.setNumber(val);
                    //加分
                    score += val;
                    if (gameListener != null){
                        gameListener.onScoreChange(score);
                        row.remove(j + 1);
                    }
                }
            }
        }

        /**
         * 根据手势处理位置坐标
         *
         * @param action
         * @param i
         * @param j
         * @return
         */
        private int getIndexByAction(ACTION action, int i, int j) {
            int index = -1;
            switch (action) {
                case UP:
                    index = i + j * column;
                    break;
                case DOWN:
                    index = column * (column - 1) + i - column * j;
                    break;
                case LEFT:
                    index = j + i * column;
                    break;
                case RIGHT:
                    index = column * i + column - 1 - j;
            }
            return index;
        }
    }
}